/**
 * created by 小卷毛, 2021-06-08
 * Copyright (c) 2021, 416143467@qq.com All Rights Reserved.
 * #                   *********                            #
 * #                  ************                          #
 * #                  *************                         #
 * #                 **  ***********                        #
 * #                ***  ****** *****                       #
 * #                *** *******   ****                      #
 * #               ***  ********** ****                     #
 * #              ****  *********** ****                    #
 * #            *****   ***********  *****                  #
 * #           ******   *** ********   *****                #
 * #           *****   ***   ********   ******              #
 * #          ******   ***  ***********   ******            #
 * #         ******   **** **************  ******           #
 * #        *******  ********************* *******          #
 * #        *******  ******************************         #
 * #       *******  ****** ***************** *******        #
 * #       *******  ****** ****** *********   ******        #
 * #       *******    **  ******   ******     ******        #
 * #       *******        ******    *****     *****         #
 * #        ******        *****     *****     ****          #
 * #         *****        ****      *****     ***           #
 * #          *****       ***        ***      *             #
 * #            **       ****        ****                   #
 */
@file:Suppress("ClassName", "unused")

package com.tim.library

import android.content.Context
import android.util.Log
import com.tencent.imsdk.v2.*
import com.tencent.qcloud.tim.tuiofflinepush.utils.BrandUtil
import com.tencent.qcloud.tim.tuiofflinepush.utils.TUIOfflinePushLog
import com.tencent.qcloud.tuicore.TUIConstants
import com.tencent.qcloud.tuicore.TUICore
import com.tencent.qcloud.tuicore.TUILogin
import com.tencent.qcloud.tuicore.interfaces.TUICallback
import com.tencent.qcloud.tuicore.interfaces.TUILoginListener
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter
import com.tim.library.third.Constants
import org.json.JSONObject

/**
 * 描 述：
 * 作 者：小卷毛  2021-06-08 11:19
 * 修改描述：
 * 修 改 人：
 * 修改版本：
 */

/**
 * IMSDK 初始化
 */
fun initIMSDK(
    context: Context,
    level: Int = V2TIMSDKConfig.V2TIM_LOG_INFO,
    listener: (Int, String?) -> Unit = { _, _ -> }
) =
    V2TIMManager
        .getInstance()
        .initSDK(
            context.applicationContext,
            Constants.TIM_APPID,
            V2TIMSDKConfig().apply {
                logLevel = level
                logListener = object : V2TIMLogListener() {
                    override fun onLog(logLevel: Int, logContent: String?) {
                        listener.invoke(logLevel, logContent)
                    }
                }
            }
        )

/**
 * 工信部要求 app 在运行期间只能获取一次设备信息。
 * 因此 app 获取设备信息设置给 SDK 后，SDK 使用该值并且不再调用系统接口。
 */
fun initBuildInfo() =
    V2TIMManager
        .getInstance()
        .callExperimentalAPI(
            "setBuildInfo",
            JSONObject().apply {
                put("buildBrand", BrandUtil.getBuildBrand())
                put("buildManufacturer", BrandUtil.getBuildManufacturer())
                put("buildModel", BrandUtil.getBuildModel())
                put("buildVersionRelease", BrandUtil.getBuildVersionRelease())
                put("buildVersionSDKInt", BrandUtil.getBuildVersionSDKInt())
            }.toString(),
            object : V2TIMValueCallback<Any> {

                override fun onSuccess(any: Any?) {
                    Log.i("callExperimentalAPI", "setBuildInfo success")
                }

                override fun onError(code: Int, desc: String?) {
                    Log.e(
                        "callExperimentalAPI",
                        "setBuildInfo code:$code desc:${
                            ErrorMessageConverter.convertIMError(
                                code,
                                desc
                            )
                        }"
                    )
                }

            }
        )

/**
 * IMSDK 登录，需要初始化
 */
fun loginIM(
    userId: String,
    userSign: String,
    listener: _V2TIMCallback.() -> Unit = {}
) =
    V2TIMManager
        .getInstance()
        .login(
            userId,
            userSign,
            _V2TIMCallback().apply(listener)
        )

/**
 * IMSDK 登出，需要初始化
 */
fun logoutIM(listener: _V2TIMCallback.() -> Unit = {}) =
    V2TIMManager.getInstance().logout(_V2TIMCallback().apply(listener))

/**
 * TUICORE 登录
 */
fun login(
    context: Context,
    userId: String,
    userSign: String,
    listener: _IUIKitCallBack.() -> Unit = {}
) =
    TUILogin.login(
        context.applicationContext,
        Constants.TIM_APPID,
        userId,
        userSign,
        _IUIKitCallBack().apply(listener)
    )

/**
 * TUICORE 登出
 */
fun logout(listener: _IUIKitCallBack.() -> Unit = {}) =
    TUILogin.logout(_IUIKitCallBack().apply(listener))

/**
 * TUICORE 登录事件监听器
 */
fun addTUILoginListener(listener: _TUILoginListener.() -> Unit = {}) =
    TUILogin.addLoginListener(_TUILoginListener().apply(listener))

/**
 * IM高级消息监听
 */
fun addAdvancedMsgListener(listener: _V2TIMAdvancedMsgListener.() -> Unit = {}) =
    V2TIMManager.getMessageManager()
        .addAdvancedMsgListener(_V2TIMAdvancedMsgListener().apply(listener))

/**
 * 组件回调的方式监听通知栏事件
 */
fun registerNotifyEvent(
    listener: (String) -> Unit = { }
) =
    TUICore
        .registerEvent(
            TUIConstants.TUIOfflinePush.EVENT_NOTIFY,
            TUIConstants.TUIOfflinePush.EVENT_NOTIFY_NOTIFICATION
        ) { key, subKey, param ->
            TUIOfflinePushLog.d(
                "registerNotify",
                "onNotifyEvent key = $key, subKey = $subKey"
            )

            if (key == TUIConstants.TUIOfflinePush.EVENT_NOTIFY) {
                if (subKey == TUIConstants.TUIOfflinePush.EVENT_NOTIFY) {
                    param?.let {
                        val extStr = it[TUIConstants.TUIOfflinePush.NOTIFICATION_EXT_KEY] as String
                        listener.invoke(extStr)
                    }
                }
            }
        }

/**
 * IM发送者消息均标记为已读
 *
 * @param sender 发送方
 */
fun cleanC2CMessageUnRead(
    sender: String, listener: _V2TIMCallback.() -> Unit = {}
) = V2TIMManager
    .getConversationManager()
    .cleanConversationUnreadMessageCount(
        String.format("c2c_%s", sender),
        0, 0,
        _V2TIMCallback().apply(listener)
    )

/**
 * IM删除本地及云端的消息
 */
fun deleteMessages(vararg message: V2TIMMessage, listener: _V2TIMCallback.() -> Unit = {}) =
    V2TIMManager
        .getMessageManager()
        .deleteMessages(
            message.toMutableList(),
            _V2TIMCallback().apply(listener)
        )

/**
 * 应用进前台时调用
 */
fun doForeground(listener: _V2TIMCallback.() -> Unit = {}) =
    V2TIMManager
        .getOfflinePushManager()
        .doForeground(_V2TIMCallback().apply(listener))

/**
 * 应用退后台时调用
 */
fun doBackground(unreadCount: Int, listener: _V2TIMCallback.() -> Unit = {}) =
    V2TIMManager
        .getOfflinePushManager()
        .doBackground(
            unreadCount,
            _V2TIMCallback().apply(listener)
        )

/**
 * TUI回调的通用接口类
 */
open class _IUIKitCallBack : TUICallback() {

    private var _onSuccess: (() -> Unit)? = null
    private var _onError: ((Int, String?) -> Unit)? = null

    fun onSuccess(listener: () -> Unit) {
        _onSuccess = listener
    }

    fun onError(listener: (Int, String?) -> Unit) {
        _onError = listener
    }

    override fun onSuccess() {
        _onSuccess?.invoke()
    }

    override fun onError(errCode: Int, errMsg: String?) {
        _onError?.invoke(errCode, errMsg)
    }

}

/**
 * TUICORE 事件监听器
 */
open class _TUILoginListener : TUILoginListener() {

    private var _onConnecting: (() -> Unit)? = null
    private var _onConnectSuccess: (() -> Unit)? = null
    private var _onConnectFailed: ((Int, String?) -> Unit)? = null
    private var _onKickedOffline: (() -> Unit)? = null
    private var _onUserSigExpired: (() -> Unit)? = null

    fun onConnecting(listener: () -> Unit) {
        _onConnecting = listener
    }

    fun onConnectSuccess(listener: () -> Unit) {
        _onConnectSuccess = listener
    }

    fun onConnectFailed(listener: (Int, String?) -> Unit) {
        _onConnectFailed = listener
    }

    fun onKickedOffline(listener: () -> Unit) {
        _onKickedOffline = listener
    }

    fun onUserSigExpired(listener: () -> Unit) {
        _onUserSigExpired = listener
    }

    /**
     * SDK 正在连接到腾讯云服务器
     *
     * The SDK is connecting to the CVM instance
     */
    override fun onConnecting() {
        _onConnecting?.invoke()
    }

    /**
     * SDK 已经成功连接到腾讯云服务器
     *
     * The SDK is successfully connected to the CVM instance
     */
    override fun onConnectSuccess() {
        _onConnectSuccess?.invoke()
    }

    /**
     * SDK 连接腾讯云服务器失败
     *
     * The SDK failed to connect to the CVM instance
     */
    override fun onConnectFailed(code: Int, error: String?) {
        _onConnectFailed?.invoke(code, error)
    }

    /**
     * 当前用户被踢下线，此时可以 UI 提示用户，并再次调用 TUILogin 的 login() 函数重新登录。
     *
     * The current user is kicked offline: the SDK notifies the user on the UI, and the user can choose to call the login() function of V2TIMManager to log in again.
     */
    override fun onKickedOffline() {
        _onKickedOffline?.invoke()
    }

    /**
     * 在线时票据过期：此时您需要生成新的 userSig 并再次调用 TUILogin 的 login() 函数重新登录。
     *
     * The ticket expires when the user is online: the user needs to generate a new userSig and call the login() function of V2TIMManager to log in again.
     */
    override fun onUserSigExpired() {
        _onUserSigExpired?.invoke()
    }
}

/**
 * IMSDK 日志实时监听
 */
open class _V2TIMLogListener : V2TIMLogListener() {

    private var _onLog: ((Int, String?) -> Unit)? = null

    fun onLog(listener: (Int, String?) -> Unit) {
        _onLog = listener
    }

    override fun onLog(logLevel: Int, logContent: String?) {
        _onLog?.invoke(logLevel, logContent)
    }
}

/**
 * IMSDK 回调的通用接口类
 */
open class _V2TIMCallback : V2TIMCallback {

    private var _onSuccess: (() -> Unit)? = null
    private var _onError: ((Int, String?) -> Unit)? = null

    fun onSuccess(listener: () -> Unit) {
        _onSuccess = listener
    }

    fun onError(listener: (Int, String?) -> Unit) {
        _onError = listener
    }

    /**
     * 成功时回调
     */
    override fun onSuccess() {
        _onSuccess?.invoke()
    }

    /**
     * 出错时回调
     *
     * @param code 错误码，详细描述请参见错误码表
     * @param desc 错误描述
     */
    override fun onError(code: Int, desc: String?) {
        _onError?.invoke(code, desc)
    }

}

/**
 * IMSDK 事件监听器
 */
open class _V2TIMSDKListener : V2TIMSDKListener() {

    private var _onConnecting: (() -> Unit)? = null
    private var _onConnectSuccess: (() -> Unit)? = null
    private var _onConnectFailed: ((Int, String?) -> Unit)? = null
    private var _onKickedOffline: (() -> Unit)? = null
    private var _onSelfInfoUpdated: ((V2TIMUserFullInfo?) -> Unit)? = null
    private var _onUserStatusChanged: ((MutableList<V2TIMUserStatus>?) -> Unit)? = null
    private var _onUserSigExpired: (() -> Unit)? = null

    fun onConnecting(listener: () -> Unit) {
        _onConnecting = listener
    }

    fun onConnectSuccess(listener: () -> Unit) {
        _onConnectSuccess = listener
    }

    fun onConnectFailed(listener: (Int, String?) -> Unit) {
        _onConnectFailed = listener
    }

    fun onKickedOffline(listener: () -> Unit) {
        _onKickedOffline = listener
    }

    fun onSelfInfoUpdated(listener: (V2TIMUserFullInfo?) -> Unit) {
        _onSelfInfoUpdated = listener
    }

    fun onUserStatusChanged(listener: (MutableList<V2TIMUserStatus>?) -> Unit) {
        _onUserStatusChanged = listener
    }

    fun onUserSigExpired(listener: () -> Unit) {
        _onUserSigExpired = listener
    }

    /**
     * SDK 正在连接到腾讯云服务器
     */
    override fun onConnecting() {
        _onConnecting?.invoke()
    }

    /**
     * SDK 已经成功连接到腾讯云服务器
     */
    override fun onConnectSuccess() {
        _onConnectSuccess?.invoke()
    }

    /**
     * SDK 连接腾讯云服务器失败
     */
    override fun onConnectFailed(code: Int, error: String?) {
        _onConnectFailed?.invoke(code, error)
    }

    /**
     * 当前用户被踢下线，此时可以 UI 提示用户，并再次调用 V2TIMManager 的 login() 函数重新登录。
     */
    override fun onKickedOffline() {
        _onKickedOffline?.invoke()
    }

    /**
     * 登录用户的资料发生了更新
     */
    override fun onSelfInfoUpdated(info: V2TIMUserFullInfo?) {
        _onSelfInfoUpdated?.invoke(info)
    }

    /**
     * 用户状态变更通知
     */
    override fun onUserStatusChanged(userStatusList: MutableList<V2TIMUserStatus>?) {
        _onUserStatusChanged?.invoke(userStatusList)
    }

    /**
     * 在线时票据过期：此时您需要生成新的 userSig 并再次调用 V2TIMManager 的 login() 函数重新登录。
     */
    override fun onUserSigExpired() {
        _onUserSigExpired?.invoke()
    }
}

open class _V2TIMAdvancedMsgListener : V2TIMAdvancedMsgListener() {

    private val mTAG = this::class.java.simpleName

    private var _onRecvNewMessage: ((V2TIMMessage) -> Unit)? = null
    private var _onRecvMessageRevoked: ((String?) -> Unit)? = null
    private var _onRecvC2CReadReceipt: ((MutableList<V2TIMMessageReceipt>?) -> Unit)? = null

    fun onRecvNewMessage(listener: (V2TIMMessage) -> Unit) {
        _onRecvNewMessage = listener
    }

    fun onRecvMessageRevoked(listener: (String?) -> Unit) {
        _onRecvMessageRevoked = listener
    }

    fun onRecvC2CReadReceipt(listener: (MutableList<V2TIMMessageReceipt>?) -> Unit) {
        _onRecvC2CReadReceipt = listener
    }

    /**
     * 收到新消息
     */
    override fun onRecvNewMessage(msg: V2TIMMessage?) {
        Log.i(mTAG, "onRecvNewMessage is called.")
        msg?.let { _onRecvNewMessage?.invoke(it) }
    }

    /**
     * 收到消息撤回的通知
     */
    override fun onRecvMessageRevoked(msgID: String?) {
        Log.i(mTAG, "onRecvMessageRevoked is called.")
        _onRecvMessageRevoked?.invoke(msgID)
    }

    /**
     * 收到 C2C 消息已读回执
     */
    override fun onRecvC2CReadReceipt(receiptList: MutableList<V2TIMMessageReceipt>?) {
        Log.i(mTAG, "onRecvC2CReadReceipt is called.")
        _onRecvC2CReadReceipt?.invoke(receiptList)
    }

}